package net.chasing.retrofit.util;

import android.text.TextUtils;

import androidx.annotation.NonNull;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;

/**
 * 请求是多线程的，这里不能设置为static，否则需要加锁，反而影响多线程请求
 */
public class ObjectUtils {
    public LinkedHashMap<String, Object> toMapWithOrder(Object obj) {
        LinkedHashMap<String, Object> params = new LinkedHashMap<>();
        toMapWithOrder(params, "", obj);
        return params;
    }

    private void toMapWithOrder(LinkedHashMap<String, Object> params, @NonNull String originalKey, Object obj) {
        if (obj == null) return;
        if (isPrimitive(obj)) {
            params.put(originalKey, obj);
            return;
        } else if (obj instanceof Map) {
            parseMapWithOrder(params, originalKey, (Map<?, ?>) obj);
            return;
        } else if (obj instanceof List) {
            parseListWithOrder(params, originalKey, (List<?>) obj);
            return;
        }

        Class<?> clazz = obj.getClass();
        List<Field> allFields = new ArrayList<>();
        Field[] temp = clazz.getDeclaredFields(); // 读取当前类的所有属性
        if (temp.length > 0) {
            allFields.addAll(Arrays.asList(temp));
        }
        while (clazz.getSuperclass() != null) {
            clazz = clazz.getSuperclass();
            if (clazz == Object.class)
                break;
            temp = clazz.getDeclaredFields();
            if (temp.length > 0) {
                allFields.addAll(Arrays.asList(temp));
            }
        }

        if (allFields.size() == 0) {
            return;
        }

        List<String> keyList = new ArrayList<>();
        List<Object> valueList = new ArrayList<>();
        try {
            for (Field field : allFields) {
                field.setAccessible(true);
                Object fieldObj = field.get(obj);
                if (fieldObj != null && !"".equals(fieldObj)) {
                    keyList.add(field.getName());
                    valueList.add(fieldObj);
                }
            }
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }

        for (int i = 0; i < keyList.size() - 1; i++) {
            for (int j = i + 1; j < keyList.size(); j++) {
                if (keyList.get(i).compareTo(keyList.get(j)) >= 1) {
                    String tempKey = keyList.get(i);
                    keyList.set(i, keyList.get(j));
                    keyList.set(j, tempKey);

                    Object tempValue = valueList.get(i);
                    valueList.set(i, valueList.get(j));
                    valueList.set(j, tempValue);
                }
            }
        }

        String key;
        Object value;
        for (int i = 0; i < keyList.size(); i++) {
            key = TextUtils.isEmpty(originalKey) ? keyList.get(i) : String.format("%s[%s]", originalKey, keyList.get(i));
            value = valueList.get(i);
            if (isPrimitive(value)) {
                params.put(key, value);
            } else if (value instanceof Map) {
                parseMapWithOrder(params, key, (Map<?, ?>) value);
            } else if (value instanceof List) {
                parseListWithOrder(params, key, (List<?>) value);
            } else {
                toMapWithOrder(params, key, value);
            }
        }

    }

    private void parseMapWithOrder(LinkedHashMap<String, Object> resultMap, String dataName, Map<?, ?> dataMap) {
        Set<?> keySet = dataMap.keySet();
        for (Object key : keySet) {
            Object value = dataMap.get(key);
            if (value != null && !"".equals(value)) {
                String keyName = TextUtils.isEmpty(dataName) ? String.format("%s", key) :
                        String.format("%s[%s]", dataName, key);
                if (isPrimitive(value)) {
                    resultMap.put(keyName, value);
                } else if (value instanceof Map) {
                    parseMapWithOrder(resultMap, keyName, (Map<?, ?>) value);
                } else if (value instanceof List) {
                    parseListWithOrder(resultMap, keyName, (List<?>) value);
                } else {
                    toMapWithOrder(resultMap, keyName, value);
                }
            }
        }
    }

    private void parseListWithOrder(LinkedHashMap<String, Object> resultMap, String dataName, List<?> dataList) {
        for (int i = 0; i < dataList.size(); i++) {
            String keyName = String.format(Locale.getDefault(), "%s[%d]", dataName, i);
            if (isPrimitive(dataList.get(i))) {
                resultMap.put(keyName, dataList.get(i));
            } else if (dataList.get(i) instanceof Map) {
                parseMapWithOrder(resultMap, keyName, (Map<?, ?>) dataList.get(i));
            } else if (dataList.get(i) instanceof List) {
                parseListWithOrder(resultMap, keyName, (List<?>) dataList.get(i));
            } else {
                toMapWithOrder(resultMap, keyName, dataList.get(i));
            }
        }
    }

    private boolean isPrimitive(Object obj) {
        return obj instanceof String || obj instanceof Boolean || obj instanceof Character ||
                obj instanceof Byte || obj instanceof Short || obj instanceof Integer ||
                obj instanceof Long || obj instanceof Float || obj instanceof Double;
    }

}